package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.NutrientDailyInfo;
import org.dtrd.modules.record.entity.bean.NutrientListInfo;
import org.dtrd.modules.record.entity.bean.NutrientRecordInfo;
import org.dtrd.modules.record.entity.bean.CheckinRecord;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninNutrientRecord;
import org.dtrd.modules.record.mapper.DtrdEntRdNutrientRecordMapper;
import org.dtrd.modules.record.service.INutrientRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@DS("multi-datasource1")
@Slf4j
public class NutrientRecordServiceImpl extends ServiceImpl<DtrdEntRdNutrientRecordMapper, DtrdEntRdSigninNutrientRecord> implements INutrientRecordService {

    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;

    @Override
    public DtrdEntRdSigninNutrientRecord transformRecord(CheckinRecord checkinRecord) {
        DtrdEntRdSigninNutrientRecord dt = new DtrdEntRdSigninNutrientRecord().init();
        dt.setNutrientRecordRemark(checkinRecord.getRemark());
        dt.setNutrientRecordDescribe(checkinRecord.getNutrientDesc());
        dt.setPatientId(checkinRecord.getPatientId());
        dt.setNutrientRecordType(checkinRecord.getSubType());
        dt.setRecordTime(parseStringAsDateTime(checkinRecord.getRecordTime()));
        dt.setRecordDate(parseStringAsDate(checkinRecord.getRecordTime()));
        dt.setNutrientRecordPhoto(checkinRecord.getImages());
        return dt;
    }

    @Override
    public CheckinRecord transformPO(DtrdEntRdSigninNutrientRecord po) {
        if (po == null) {
            return null;
        }
        CheckinRecord checkinRecord = new CheckinRecord();
        checkinRecord.setRecordTime(DateUtils.formatTime(po.getRecordTime()));
        checkinRecord.setRecordTimeHm(DateUtils.formatShortTime(po.getRecordTime()));
        checkinRecord.setDataId(po.getDataId());
        checkinRecord.setImages(po.getNutrientRecordPhoto());
        checkinRecord.setPatientId(po.getPatientId());
        checkinRecord.setRecordType(Constant.RecordType.NUTRIENT.getType());
        checkinRecord.setRecordTypeName(Constant.RecordType.NUTRIENT.getName());
        checkinRecord.setRemark(po.getNutrientRecordRemark());
        checkinRecord.setNutrientDesc(po.getNutrientRecordDescribe());
        return checkinRecord;
    }

    @Override
    public LambdaQueryWrapper<DtrdEntRdSigninNutrientRecord> generateSelectRecordByDateQuery(Integer patientId, String date, Integer subType) {
        LambdaQueryWrapper<DtrdEntRdSigninNutrientRecord> query = new LambdaQueryWrapper<>();
        query.eq(DtrdEntRdSigninNutrientRecord::getIsDel, 0)
                .eq(DtrdEntRdSigninNutrientRecord::getPatientId,patientId)
                .eq(DtrdEntRdSigninNutrientRecord::getRecordDate, date).eq(DtrdEntRdSigninNutrientRecord::getNutrientRecordType, subType);
        return query;
    }

    @Override
    public boolean saveOrUpdateNutrientRecord(NutrientRecordInfo nutrientRecordInfo) {
        Integer patientId = nutrientRecordInfo.getPatientId();
        DtrdEntRdSigninNutrientRecord po = new DtrdEntRdSigninNutrientRecord();
        if (nutrientRecordInfo.getDataId() == null) {
            po = po.init();
        }
        po = po.parseFromDto(nutrientRecordInfo);
        Date recordDate = po.getRecordDate();
        LambdaUpdateWrapper<DtrdEntRdSigninNutrientRecord> wrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninNutrientRecord.class)
                .eq(DtrdEntRdSigninNutrientRecord::getNutrientRecordType, nutrientRecordInfo.getNutrientRecordType())
                .eq(DtrdEntRdSigninNutrientRecord::getRecordDate, recordDate)
                .eq(DtrdEntRdSigninNutrientRecord::getPatientId, patientId);
        boolean result = saveOrUpdate(po, wrapper);
        if (po.getDataId() == null) {
            po = getOne(wrapper);
        }
        // 打卡
        signinRecordService.saveSigninRecord(po.getDataId(), nutrientRecordInfo.getNutrientRecordType(), mapper ->
                mapper.apply(patientId)
                        .withRecordType(Constant.RecordType.NUTRIENT.getType())
                        .withRecordTime(DateUtils.formatDate(nutrientRecordInfo.getRecordTime(),DateUtils.datetimeFormat.get().toPattern()))
                        .withRecordDesc(nutrientRecordInfo.getNutrientRecordDescribe())
                        .withRemark(nutrientRecordInfo.getNutrientRecordRemark())
                        .withImages(nutrientRecordInfo.getNutrientRecordPhoto())
                        .build()
        );
        return result;
    }

    @Override
    public List<NutrientDailyInfo> getNutrientRecordList(Integer pageNum, Integer pageSize, Integer patientId, String startDate, String endDate) {
        List<DtrdEntRdSigninNutrientRecord> list = baseMapper.getNutrientRecordList(patientId, startDate, endDate);
        if (list.size() > 0) {
            List<NutrientDailyInfo> dataList = new ArrayList<>(list.size() / 2);
            TreeMap<String, List<DtrdEntRdSigninNutrientRecord>> recordMap = new TreeMap<>(Collections.reverseOrder());
            list.forEach(value -> {
                String date = DateUtils.formatDate(value.getRecordDate());
                List<DtrdEntRdSigninNutrientRecord> dataRecordList = recordMap.get(date);
                if (dataRecordList == null) {
                    dataRecordList = new ArrayList<>(4);
                }
                dataRecordList.add(value);
                recordMap.put(date, dataRecordList);
            });
            if (MapUtil.isNotEmpty(recordMap)) {
                Set<String> keySet = recordMap.keySet();
                keySet.forEach(date -> {
                    NutrientDailyInfo nutrientDailyInfo = new NutrientDailyInfo();
                    nutrientDailyInfo.setRecordDate(date);
//                    nutrientDailyInfo.setPatientId(patientId);
                    List<DtrdEntRdSigninNutrientRecord> dataRecord = recordMap.get(date);
                    for (DtrdEntRdSigninNutrientRecord nutrientRecord : dataRecord) {
                        Constant.NutrientRecordType nutrientRecordType = Constant.NutrientRecordType.valueOf(nutrientRecord.getNutrientRecordType());
                        assert nutrientRecordType != null;
                        switch (nutrientRecordType) {
                            case MORNING:
                                nutrientDailyInfo.setRecordTimeMorning(nutrientRecord.getRecordTime());
                                nutrientDailyInfo.setNutrientMorningDesc(nutrientRecord.getNutrientRecordDescribe());
                                nutrientDailyInfo.setNutrientMorningPhoto(nutrientRecord.getNutrientRecordPhoto());
                                nutrientDailyInfo.setNutrientRecordMorning(new NutrientRecordInfo().parseFromPo(nutrientRecord));
                                break;
                            case NOON:
                                nutrientDailyInfo.setRecordTimeNoon(nutrientRecord.getRecordTime());
                                nutrientDailyInfo.setNutrientNoonDesc(nutrientRecord.getNutrientRecordDescribe());
                                nutrientDailyInfo.setNutrientNoonPhoto(nutrientRecord.getNutrientRecordPhoto());
                                nutrientDailyInfo.setNutrientRecordNoon(new NutrientRecordInfo().parseFromPo(nutrientRecord));
                                break;
                            case EVENING:
                                nutrientDailyInfo.setRecordTimeNight(nutrientRecord.getRecordTime());
                                nutrientDailyInfo.setNutrientNightDesc(nutrientRecord.getNutrientRecordDescribe());
                                nutrientDailyInfo.setNutrientNightPhoto(nutrientRecord.getNutrientRecordPhoto());
                                nutrientDailyInfo.setNutrientRecordNight(new NutrientRecordInfo().parseFromPo(nutrientRecord));
                                break;
                            case SLEEP:
                                nutrientDailyInfo.setRecordTimeBeforeSleep(nutrientRecord.getRecordTime());
                                nutrientDailyInfo.setNutrientBeforeSleepDesc(nutrientRecord.getNutrientRecordDescribe());
                                nutrientDailyInfo.setNutrientBeforeSleepPhoto(nutrientRecord.getNutrientRecordPhoto());
                                nutrientDailyInfo.setNutrientRecordBeforeSleep(new NutrientRecordInfo().parseFromPo(nutrientRecord));
                                break;
                            default:
                                break;
                        }
                    }
                    dataList.add(nutrientDailyInfo);
                });
                // 处理分页
                assert pageNum != null;
                assert pageSize != null;
                int pageStart = (pageNum-1) * pageSize;
                ArrayList<NutrientDailyInfo> resultList = new ArrayList<>(pageSize);
                int range = Math.min(pageNum * pageSize, dataList.size());
                for (int i = pageStart; i < range; i++) {
                    resultList.add(dataList.get(i));
                }
                return resultList;
            }
        }
        return null;
    }

    @Override
    public Integer getNutrientRecordDataCount(Integer patientId, String startDate, String endDate) {
        return baseMapper.countGroupNutrientRecord(patientId, startDate, endDate);
    }

    @Override
    public DtrdEntRdSigninNutrientRecord getNutrientRecordLatestByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdSigninNutrientRecord> wrapper = Wrappers.lambdaQuery(DtrdEntRdSigninNutrientRecord.class)
                .eq(DtrdEntRdSigninNutrientRecord::getPatientId, patientId)
                .orderByDesc(DtrdEntRdSigninNutrientRecord::getCreateTime)
                .last("limit 1");
        return getOne(wrapper);
    }

}
